﻿//
// Ultralight namespace
//
var Ultralight = {};

//
// converter
//
// Wraps all "globals" so that the only thing
// exposed is makeHtml().
//
Ultralight.converter = function() {
	var LineBreakPattern=/^\n{1,}/;
	var LinkPattern=/^\[([^\]\n]+)\]\((\w+:\/\/[^)\n]+)\)/;
	var BoldPattern=/^\*\*[^*\n]+\*\*/;
	var ItalicPattern=/^\*[^*\n]+\*/;
	var ListPattern=/^- [^\n]+/;
	var CodePattern=/^[ ]{4}.*/;
	var InlineCodePattern=/^`[^`\n]+`/;
	var QuotePattern=/^&gt; .*/;

	var linefeed = String.fromCharCode(10);

	this.makeHtml = function(text, skipEncoding)
	{
		var html;
		if (skipEncoding)
		{
			var html = new String(text);
		}
		else
		{
			//html encode, then replace crlf with line feeds, and replace tabs with 4 spaces		
			var html = new String(text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\r\n/g,'\n').replace(/\t/g,'    '));
		}
		var htmlLength = html.length;
		var transformed_html = "";
		var skip_to = 0;
		var i = 0;
		var currentChar = "";
		var result = null;
		var precedingLineOrStart = true;

		while (i < htmlLength)
		{
			precedingLineOrStart = (i == 0 || currentChar == linefeed);
			currentChar = html.charAt(i);

			if (currentChar == linefeed)
			{
				// line feeds
				result = LineBreakPattern.exec(html.substring(i));
				if (result != null && result.length > 0)
				{
					skip_to = i + result[0].length;
					if (result[0].length > 1)
						transformed_html += "<br /><br />";
					else
						transformed_html += "<br />";
				}				
			}
			else if (precedingLineOrStart && currentChar == " " && html.substr(i,4) == "    ")
			{
				// code
				result = CodePattern.exec(html.substring(i));
				if (result != null && result.length > 0 && result[0].length > 4)
				{
					skip_to = i;
										
					transformed_html += '<pre class="prettyprint"><code>';
					var code = new String("");
					do
					{
						skip_to += result[0].length + 1; // the plus one accounts for the line feed that's not captured
						if (code.length > 0) code += "<br/>";
						code += result[0].replace(/^[ ]{4}/, "");
						result = CodePattern.exec(html.substring(skip_to));
					}
					while (result != null && result.length > 0 && result[0].length > 3);
					transformed_html += code;
					transformed_html += '</code></pre>';
				}
			}			
			else if (precedingLineOrStart && currentChar == "-")
			{
				// list
				result = ListPattern.exec(html.substring(i));
				if (result != null && result.length > 0 && result[0].length > 2)
				{
					skip_to = i;

					transformed_html += '<ul>';
					do
					{						
						skip_to += result[0].length + 1; // the plus one accounts for the line feed that's not captured
						var linecontent = result[0].replace(/^- /, '');
						if (linecontent.length > 0)
						{
							transformed_html += '<li>';
							transformed_html += this.makeHtml(linecontent, true);
							transformed_html += '</li>';
						}
						result = ListPattern.exec(html.substring(skip_to));
					}
					while (result != null && result.length > 0 && result[0].length > 2);
					transformed_html += '</ul>';
				}
			}
			else if (currentChar == "[")
			{
				// link
				result = LinkPattern.exec(html.substring(i));
				if (result != null && result.length > 2)
				{
					skip_to = i + result[0].length;
					var linktitle = result[1];
					var link = result[2];
					transformed_html += '<a href="' + link + '" target="_blank" rel="nofollow">';
					transformed_html += linktitle;
					transformed_html += '</a>';
				}
			}
			else if (currentChar == "`")
			{
				// inline code
				result = InlineCodePattern.exec(html.substring(i));
				if (result != null && result.length > 0)
				{
					skip_to = i + result[0].length;
					transformed_html += '<code class="prettyprint">';
					transformed_html += result[0].substring(1, result[0].length - 1);
					transformed_html += '</code>';
				}
			}
			else if (currentChar == "*")
			{
				// bold
				result = BoldPattern.exec(html.substring(i));						
				if (result != null && result.length > 0)
				{
					//WriteToConsole(result[0]);
					skip_to = i + result[0].length;
					transformed_html += '<b>';
					transformed_html += result[0].substring(2, result[0].length - 2);
					transformed_html += '</b>';
				}
				else
				{
					// italic
					result = ItalicPattern.exec(html.substring(i));
					if (result != null && result.length > 0)
					{
						skip_to = i + result[0].length;
						transformed_html += '<i>';
						transformed_html += result[0].substring(1, result[0].length - 1);
						transformed_html += '</i>';
					}
				}
			}
			else if (precedingLineOrStart && currentChar == "&" && html.substr(i,4) == "&gt;")
			{
				// blockquote
				result = QuotePattern.exec(html.substring(i));						
				if (result != null && result.length > 0 && result[0].length > 4)
				{
					skip_to = i;

					transformed_html += '<blockquote>';
					var quote = new String("");
					do
					{
						skip_to += result[0].length + 1; // the plus one accounts for the line feed that's not captured
						if (quote.length > 0) quote += "<br/>";
						quote += result[0].replace(/^&gt; /, "");
						result = QuotePattern.exec(html.substring(skip_to));
					}
					while (result != null && result.length > 0 && result[0].length > 3);
					transformed_html += quote;
					transformed_html += '</blockquote>';
				}
			}

			if (i >= skip_to)
			{
				transformed_html += currentChar;
				i++;
			}
			else
			{
				i = skip_to;
			}
		}		

		return transformed_html;
	}
}
